package com.common.utils.http;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;

/**
 * 
 * @author feijinbo
 * @creatTime 2011-7-5下午02:53:17
 * @desc http异步调用
 */
public class AsyncHttpClient {

	// 超时等待
	private static final int CONNECTION_TIMEOUT = 5000;

	// 默认字符集
	private static final String CONTENT_CHARSET = "UTF-8";

	private String encoding;// 字符编码

	/**
	 * Using asynchronously GET method.
	 * 
	 * @param url
	 *            The remote URL.
	 * @param queryString
	 *            The query string containing parameters
	 * @param callback
	 *            Callback handler.
	 * @param cookie
	 *            Cookie response to handler.
	 * @return Whether request has started.
	 */
	public boolean httpGet(String url, String queryString,
			AsyncHandler callback, Object cookie) {
		if (url == null || url.equals("")) {
			return false;
		}
		if (queryString != null && !queryString.equals("")) {
			url += "?" + queryString;
		}
		GetMethod httpGet = new GetMethod(url);
		httpGet.getParams().setParameter("http.socket.timeout",
				new Integer(CONNECTION_TIMEOUT));
		mThreadPool.submit(new AsyncThread(httpGet, callback, cookie));
		return true;
	}

	/**
	 * Using asynchronously POST method.
	 * 
	 * @param url
	 *            The remote URL.
	 * @param queryString
	 *            The query string containing parameters
	 * @param callback
	 *            Callback handler.
	 * @param cookie
	 *            Cookie response to handler.
	 * @return Whether request has started.
	 */
	public boolean httpPost(String url, String queryString,
			AsyncHandler callback, Object cookie) {
		if (url == null || url.equals("")) {
			return false;
		}
		PostMethod httpPost = new PostMethod(url);
		httpPost.addParameter("Content-Type",
				"application/x-www-form-urlencoded");
		httpPost.getParams().setParameter("http.socket.timeout",
				new Integer(CONNECTION_TIMEOUT));
		// 设置字符集
		if (this.encoding != null && !this.encoding.equals("")) {
			httpPost.addRequestHeader("Content-Type", "text/html; charset="
					+ this.encoding);
		} else {
			httpPost.addRequestHeader("Content-Type", "text/html; charset="
					+ CONTENT_CHARSET);
		}
		if (queryString != null && !queryString.equals("")) {
			httpPost.setRequestEntity(new ByteArrayRequestEntity(queryString
					.getBytes()));
		}
		mThreadPool.submit(new AsyncThread(httpPost, callback, cookie));
		return true;
	}

	@SuppressWarnings("rawtypes")
	public boolean httpPost(String url, List parameters, AsyncHandler callback,
			Object cookie) {
		if (url == null || url.equals("")) {
			return false;
		}
		PostMethod httpPost = new PostMethod(url);
		httpPost.addParameter("Content-Type",
				"application/x-www-form-urlencoded");
		httpPost.getParams().setParameter("http.socket.timeout",
				new Integer(CONNECTION_TIMEOUT));
		// 设置字符集
		httpPost.getParams().setParameter(
				HttpMethodParams.HTTP_CONTENT_CHARSET, CONTENT_CHARSET);
		// 添加请求参数.
		for (Iterator iter = parameters.iterator(); iter.hasNext();) {
			Parameter para = (Parameter) iter.next();
			httpPost.addParameter(para.mName == null ? "" : para.mName,
					para.mValue == null ? "" : para.mValue);
		}
		mThreadPool.submit(new AsyncThread(httpPost, callback, cookie));
		return true;
	}

	/**
	 * Using asynchronously POST method with multiParts.
	 * 
	 * @param url
	 *            The remote URL.
	 * @param queryString
	 *            The query string containing parameters
	 * @param callback
	 *            Callback handler.
	 * @param cookie
	 *            Cookie response to handler.
	 * @return Whether request has started.
	 */
//	public boolean httpPostWithFile(String url, String queryString,
//			List<Parameter> files, AsyncHandler callback, Object cookie) {
//		if (url == null || url.equals("")) {
//			return false;
//		}
//		url += '?' + queryString;
//		PostMethod httpPost = new PostMethod(url);
//		List<Parameter> listParams = HttpUtil.getQueryParameters(queryString);
//		int length = listParams.size() + (files == null ? 0 : files.size());
//		Part[] parts = new Part[length];
//		int i = 0;
//		for (Parameter param : listParams) {
//			parts[i++] = new StringPart(param.mName, param.mValue,
//					CONTENT_CHARSET);
//		}
//		try {
//			for (Parameter param : files) {
//				File file = new File(param.mValue);
//				parts[i++] = new MyFilePart(param.mName, file.getName(), file,
//						HttpUtil.getContentType(file), CONTENT_CHARSET);
//			}
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//			return false;
//		}
//
//		httpPost.setRequestEntity(new MultipartRequestEntity(parts, httpPost
//				.getParams()));
//		mThreadPool.submit(new AsyncThread(httpPost, callback, cookie));
//		return true;
//	}

	private ExecutorService mThreadPool = Executors.newFixedThreadPool(20);

	/**
	 * Thread for asynchronous HTTP request.
	 * 
	 */
	class AsyncThread extends Thread {
		private HttpMethod mHttpMedthod;
		private AsyncHandler mAsyncHandler;
		private Object mCookie;

		public AsyncThread(HttpMethod method, AsyncHandler handler,
				Object cookie) {
			this.mHttpMedthod = method;
			this.mAsyncHandler = handler;
			this.mCookie = cookie;
		}

		@Override
		public void run() {
			String responseData = null;
			HttpClient httpClient = new HttpClient();
			int statusCode = -1;
			try {
				statusCode = httpClient.executeMethod(mHttpMedthod);
				if (statusCode != HttpStatus.SC_OK) {
					System.err.println("HttpMethod failed: "
							+ mHttpMedthod.getStatusLine());
				}
				responseData = mHttpMedthod.getResponseBodyAsString();
			} catch (HttpException e) {
				e.printStackTrace();
				if (mAsyncHandler != null) {
					mAsyncHandler.onThrowable(e, mCookie);
				}
				return;
			} catch (IOException e) {
				e.printStackTrace();
				if (mAsyncHandler != null) {
					mAsyncHandler.onThrowable(e, mCookie);
				}
				return;
			} finally {
				mHttpMedthod.releaseConnection();
				httpClient = null;
			}
			if (mAsyncHandler != null) {
				mAsyncHandler.onCompleted(statusCode, responseData, mCookie);
			}
		}

	}

	/**
	 * @return the encoding
	 */
	public String getEncoding() {
		return encoding;
	}

	/**
	 * @param encoding
	 *            the encoding to set
	 */
	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}
}
